package dm.ast.model.gen.factory;

import test.utility.Randomly;

import java.util.ArrayList;
import java.util.List;

/**
 * @author scy
 * @date 2024/4/16
 * 表达式的复杂度模板设置
 */
public class ExpressionModelFactory extends BaseModelFactory {
    //根据宽度、深度返回from模型
    public static ComplexityModel expModels(int wid_t, int dep_t) {
        List<ComplexityModel> models = new ArrayList<ComplexityModel>();
        //1、极值分配
        models.addAll(modelExtreme(wid_t, dep_t));

        //2、深度平均分配
        if (wid_t > estimateMinWidt(dep_t) && dep_t > 1) {
            models.addAll(modelAverage(wid_t, dep_t));
        }

        return Randomly.fromList(models);
    }

    //极值分配
    public static List<ComplexityModel> modelExtreme(int wid_t, int dep_t) {
        List<ComplexityModel> extreme = new ArrayList<ComplexityModel>();
        ComplexityModel model;

        //仅一个表达式
        model = new ComplexityModel(1);
        model.comps[0].wid_t = wid_t;
        model.comps[0].dep_t = dep_t;
        extreme.add(model);

        //尽可能多的bool表达式，随便选择一个表达式深度设为dep_t
        int maxDept_widt = setWidtByDept(dep_t);
        if (wid_t > maxDept_widt) {
            model = new ComplexityModel((wid_t - maxDept_widt) / FactoryConstant.MIN_EXP_WIDT + 1);
            for (int i = 0; i < model.count; i++) {
                model.comps[i].wid_t = 1;
                model.comps[i].dep_t = 1;
            }
            int j = r.getInteger(0, model.count);
            model.comps[j].dep_t = dep_t;
            model.comps[j].wid_t = maxDept_widt;
            extreme.add(model);
        }
        return extreme;
    }

    //深度平均分配
    public static List<ComplexityModel> modelAverage(int wid_t, int dep_t) {
        List<ComplexityModel> average = new ArrayList<ComplexityModel>();
        ComplexityModel model = new ComplexityModel(wid_t / FactoryConstant.MIN_WIDT_COMP + 1);
        //需要考虑多深度时wid的变化
        int tmp_widt_used = 0;
        for (int i = 0; i < model.count; i++) {
            model.comps[i].dep_t = r.getInteger(1, dep_t + 1);
            model.comps[i].wid_t = setWidtByDept(model.comps[i].dep_t);
            tmp_widt_used += model.comps[i].wid_t;
            if (tmp_widt_used >= wid_t) {  //宽度已经达到要求，那么终止
                break;
            }

        }
        average.add(model);
        return average;
    }
}
